/* 
 * TxCtrl.c
 * Created on March 9, 2008; 8:18 PM
 * by VRamadurai
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <pthread.h>
#include <machine/machdefs.h>
#include <sched.h>
#include <os/osapi.h>
#include <os/hstream.h>
#include <machine/mmio.h>

#include "iqdma_3500.h"

/** MAC Header files**/
#include "hs_types.h"
#include "HsTypes.h"
#include "PhyConstants.h"
#include "PhyStruct.h"
#include "PmdGlobals.h"
#include "wlan_phy_mac.h"
#include "crc32_sb.h"
#include "icrdefs_3500.h"

#define N_HEAD_SYMS		8 //INITIAL SYMBOLS before DMA start
#define HEADER_SYMBOLS              (PLCP_PREAMBLE_BITS + PLCP_SFD_BITS)
#define SHORT_HEADER_SYMBOLS        (PLCP_SHORT_PREAMBLE_BITS + PLCP_SFD_BITS)

hs_int16_t HeaderSamplesI[HEADER_SYMBOLS*22] = 
{
    #include "header_i.h"
};

hs_int16_t HeaderSamplesQ[HEADER_SYMBOLS*22] = 
{
    #include "header_q.h"
};


hs_int16_t ShortHeaderSamplesI[SHORT_HEADER_SYMBOLS*22] = 
{
    #include "short_header_i.h"
};

hs_int16_t ShortHeaderSamplesQ[SHORT_HEADER_SYMBOLS*22] = 
{
    #include "short_header_q.h"
};


/* Tx Related variables */

struct HS_PhyTx11bStr  *volatile HS_PhyTx11bPtr;

extern volatile hs_int32_t start_transmit;
volatile hs_int32_t StrCreateTxFlag;

hs_int16_t DacOutI[GLOBAL_BUF_SIZE];   
hs_int16_t DacOutQ[GLOBAL_BUF_SIZE];

void send_header_iq(
                        hs_int16_t * restrict srcI,                        
                        hs_int16_t * restrict dstI,
                        hs_int16_t * restrict srcQ,                        
                        hs_int16_t * restrict dstQ
                    )
{
    hs_int32_t i;        
   
    /** Send 8 header symbols: 1 sub-buffer **/
    for(i=0; i<N_HEAD_SYMS*22; i++){
        dstI[i] = srcI[i];
        dstQ[i] = srcQ[i];       
    }   
}

void *TxCtrl(void *arg)
{    
    /* Tx Start processing */
    /* Initialising the structure creation flags */     
    
    hs_int32_t siPrevAddr;
    hs_int32_t tot_samps;
    hs_int32_t count_samps;
    hs_int32_t rate;
    
    struct HS_PhyTx11bStr  sPhyTx11bStr;
    
    hs_int16_t *d2a_beginI;
    hs_int16_t *d2a_beginQ;
    
    hs_int32_t i;   
    
    struct HS_PhyTx11bStr  *volatile HS_PhyTx11bPtrMain;
    hs_int32_t NumTxSamples;
    hs_int32_t siPayLoadLength;
   
    /* RF Related variables*/
    hs_int16_t  *pssGlobalBufI;
    hs_int16_t  *pssGlobalBufQ;
    hs_int32_t  siFinalAddr;   
   
    hs_int32_t siStartAddrI;
    hs_int32_t siInitAddrI;
    
    hs_uint32_t base = ICR_ADDRESS_CORE(2);
    
    HS_PhyTx11bPtr = &(sPhyTx11bStr) ;
    HS_PhyTx11bPtrMain = HS_PhyTx11bPtr;    
    HS_PhyTx11bPtrMain->psTxDtoAStartI = &DacOutI[0];
    HS_PhyTx11bPtrMain->psTxDtoAStartQ = &DacOutQ[0];
    HS_PhyTx11bPtrMain->psTxDtoAEndI = &DacOutI[GLOBAL_BUF_SIZE];
    
    /* Check the D2A buffers' address alignment anyway */
    if( ((hs_int32_t)DacOutI & RF_SUBB_ALIGN) ||
       ((hs_int32_t)DacOutQ & RF_SUBB_ALIGN))
    {
       fprintf(stderr,"RF buffers not aligned\n");
       fprintf(stderr,"%p %p %d %d\n", DacOutI, DacOutQ,
                ((hs_int32_t)DacOutI & RF_SUBB_ALIGN),
                ((hs_int32_t)DacOutQ & RF_SUBB_ALIGN));
       exit (-28);
    }          

    for(i=0; i<1; i++){
          HS_PhyTx11bPtrMain->siTxMas2Slave[i] = 0;
          HS_PhyTx11bPtrMain->siTxSlave2Mas[i] = 0;
    }    
    
    HS_PhyTx11bPtrMain->HeaderSamplesI = HeaderSamplesI;
    HS_PhyTx11bPtrMain->HeaderSamplesQ = HeaderSamplesQ;
    HS_PhyTx11bPtrMain->ShortHeaderSamplesI = ShortHeaderSamplesI;
    HS_PhyTx11bPtrMain->ShortHeaderSamplesQ = ShortHeaderSamplesQ;
    HS_PhyTx11bPtrMain->header_iq_offset = N_HEAD_SYMS*22; //8 symbols
    	
    StrCreateTxFlag = 1;    
    
    /*setting the initial and final address of the global buffers*/
    pssGlobalBufI =(hs_int16_t *)(&(DacOutI[0]));
    pssGlobalBufQ =(hs_int16_t *)(&(DacOutQ[0]));
    siStartAddrI  = (hs_int32_t)(&(DacOutI[0]));
    siInitAddrI   = siStartAddrI;

    /*  DMA  settings */  
    /* set I buffer start address */
    ICR_SET(base, REG_D2AISTR, (unsigned)DacOutI);
    /* set Q buffer start address */
    ICR_SET(base, REG_D2AQSTR, (unsigned)DacOutQ);      
  
    //HS_PhyTx11bPtrMain->preamble_type = SHORT_PREAMBLE;
    HS_PhyTx11bPtrMain->preamble_type = LONG_PREAMBLE;    
    
    HS_PhyTx11bPtrMain->psTxDtoABufferI = pssGlobalBufI + N_HEAD_SYMS*22; //8 symbols
    HS_PhyTx11bPtrMain->psTxDtoABufferQ = pssGlobalBufQ + N_HEAD_SYMS*22; //8 symbols  
    
    d2a_beginI = HS_PhyTx11bPtrMain->psTxDtoABufferI;
    d2a_beginQ = HS_PhyTx11bPtrMain->psTxDtoABufferQ;   
        
    while(1)
    {        
        /** Handle precomputed header part **/
        if(HS_PhyTx11bPtrMain->preamble_type == LONG_PREAMBLE){
            send_header_iq(HeaderSamplesI, DacOutI, HeaderSamplesQ, DacOutQ);
        }
        else{
            send_header_iq(ShortHeaderSamplesI, DacOutI, ShortHeaderSamplesQ, DacOutQ);
        }
    
        HS_PhyTx11bPtrMain->psTxDtoABufferI = d2a_beginI;
        HS_PhyTx11bPtrMain->psTxDtoABufferQ = d2a_beginQ;
        
        HS_PhyTx11bPtrMain->ssTxStart2Sync = 0;                

        while(start_transmit == 0){
            for(i=0; i<8; i++)
                __sb_barrier();
        }        
        
        //__putstring("Tx: len = %d\n", mac2phy_struct.mac2phy_tx_len);
        
        /* Start only main thread */       
        HS_PhyTx11bPtrMain->siTxMas2Slave[0] = 1;                                      
               
        /** Start the D2A IQDMA **/
        /* set the buffer size and count and start the IQ DMA */
        ICR_SET(base,
                    REG_D2ACTL,
                    D2A_CTL_ENABLEI
                    |D2A_CTL_ENABLEQ
                    |D2A_CTL_DECIMATION(0)
                    |D2A_CTL_BUFSIZE(SUB_BUF_SIZE-4)
                    |D2A_CTL_BUFCOUNT(NSUBFS-1));         
        
      
        siPayLoadLength = mac2phy_struct.mac2phy_tx_len;             
        rate = mac2phy_struct.mac2phy_tx_rate;	

        if(HS_PhyTx11bPtrMain->preamble_type == LONG_PREAMBLE){
            /* DataRate; */
            if(rate == 10)
            {
               //__putstring("Running Tx 1 MBPS  . . .");
               NumTxSamples = 192*22 + siPayLoadLength*8*22;
               //siPayLoadSymbols =siPayLoadLength*8;
            }
            else if(rate == 20)
            {
               //__putstring("Running Tx 2 MBPS . . . ");
               NumTxSamples = 192*22 + siPayLoadLength*4*22;
               //siPayLoadSymbols =siPayLoadLength*4;
            }
            else if(rate == 55)
            {
               //__putstring("Running Tx 5.5 MBPS . . . ");
               NumTxSamples = 192*22 + siPayLoadLength*2*16;
               //siPayLoadSymbols =siPayLoadLength*2;
            }
            else if(rate == 110)
            {
               //__putstring("Running Tx 11 MBPS . . .");
               NumTxSamples = 192*22 + siPayLoadLength*16;
               //siPayLoadSymbols =siPayLoadLength;
            }
            else
            {
               //__putstring("\n\n   * * * * * Invalid data Rate * * * * * \n\n\n");
               exit(-1);
            }// I/p Ref file   
        }
        else{
            /* DataRate; */
            if(rate == 10)
            {
               //__putstring("Running Tx 1 MBPS  . . .");
               NumTxSamples = (56+16+24)*22 + siPayLoadLength*8*22;
               //siPayLoadSymbols =siPayLoadLength*8;
            }
            else if(rate == 20)
            {
               //__putstring("Running Tx 2 MBPS . . . ");
               NumTxSamples = (56+16+24)*22 + siPayLoadLength*4*22;
               //siPayLoadSymbols =siPayLoadLength*4;
            }
            else if(rate == 55)
            {
               //__putstring("Running Tx 5.5 MBPS . . . ");
               NumTxSamples = (56+16+24)*22 + siPayLoadLength*2*16;
               //siPayLoadSymbols =siPayLoadLength*2;
            }
            else if(rate == 110)
            {
               //__putstring("Running Tx 11 MBPS . . .");
               NumTxSamples = (56+16+24)*22 + siPayLoadLength*16;
               //siPayLoadSymbols =siPayLoadLength;
            }
            else
            {
               //__putstring("\n\n   * * * * * Invalid data Rate * * * * * \n\n\n");
               exit(-1);
            }// I/p Ref file   
        }
        //__putstring("Tx samples = %d\n", NumTxSamples);        
        
        siPrevAddr = (hs_int32_t)siInitAddrI;

        /** Wait for Total samples to be Txmitted **/
        tot_samps = 0;                                                         
        
        while(1)
        {
            siFinalAddr = ICR_GET(base,REG_D2AISTR) | CORE_ADDR_BASE(2);
            
            if((count_samps = siFinalAddr - siPrevAddr) >= 0){
                siPrevAddr = siFinalAddr;
                tot_samps += count_samps;
            }
            else{
                siPrevAddr = siFinalAddr;
                tot_samps += (GLOBAL_BUF_SIZE*sizeof(short) + count_samps);
            }          

            if(tot_samps > NumTxSamples*sizeof(short)){
            	break;
            }                
        }                                   
             
        osFastPause(50);                
        
        /** Stop the D2A **/
        ICR_SET(base, REG_D2ACTL, 0);        
        
        while(HS_PhyTx11bPtrMain->siTxSlave2Mas[0] == 0){
            __sb_barrier();
        }                    
        HS_PhyTx11bPtrMain->siTxSlave2Mas[0] = 0;
        
        start_transmit = 0;  
    }    
}
      
